package com.multimedia.scala

/** Quick sort, imperative style */
object Sort {

  /** 
   *  Nested methods can use and even update everything 
   *  visible in their scope (including local variables or 
   *  arguments of enclosing methods). 
   */
  def Sort(a: Array[Int]) {

    def swap(i: Int, j: Int) {
      val t = a(i); a(i) = a(j); a(j) = t
    }

    def sort1(l: Int, r: Int) {
      val pivot = a((l + r) / 2)
      var i = l
      var j = r
      while (i <= j) {
        while (a(i) < pivot) i += 1
        while (a(j) > pivot) j -= 1
        if (i <= j) {
          swap(i, j)
          i += 1
          j -= 1
        }
      }
      if (l < j) sort1(l, j)
      if (j < r) sort1(i, r)
    }

    if (a.length > 0)
      sort1(0, a.length - 1)
  }

  def println(ar: Array[Int]) {
    def print1 = {
      def iter(i: Int): String =
        ar(i) + (if (i < ar.length-1) "," + iter(i+1) else "")
      if (ar.length == 0) "" else iter(0)
    }
    Console.println("[" + print1 + "]")
  }

    
    /** merge sort */
    def msort[A](less : (A, A)=>Boolean)(xs: List[A]): List[A] = {
        def merge(xs1: List[A], xs2: List[A]): List[A] = 
          if (xs1.isEmpty) xs2
          else if (xs2.isEmpty) xs1
          else if (less(xs1.head, xs2.head)) xs1.head :: merge(xs1.tail, xs2)
          else xs2.head :: merge(xs1, xs2.tail)
        
        val n = xs.length/2
        if (n==0) xs
        else merge(msort(less)(xs take n), msort(less)(xs drop n))
    }

    /** insertion sort */
    def isort(xs: List[Int]): List[Int] = {
      def insert(x: Int, xs: List[Int]): List[Int] = xs match {
        case List() => List(x)
        case y::ys => if(x<=y)x::xs else y::insert(x, ys)
      }
      xs match {
        case List() => List()
        case x::xs1 => insert(x, isort(xs1))
      }
    }

	def main(args: Array[String]) {
	    val ar = Array(6, 2, 8, 5, 1)
	    println(ar)
	    Sort(ar)
	    println(ar)
	}

}